package top.guoyang.springboot3.exception;


import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.resource.NoResourceFoundException;
import top.guoyang.springboot3.base.R;


import java.sql.SQLException;
import java.util.List;


/**
 * 全局异常处理
 *
 * @author yangguo
 */
@Slf4j
//控制器拦截器，所有控制器的方法都会被本类拦截
@ControllerAdvice
public class AppExceptionHandler {


    //@ExceptionHandler是异常处理器，当控制器抛出对应类型的异常时会触发本方法
    @ExceptionHandler(Exception.class)
    //@ResponseBody  表示应答结果以json格式返回
    @ResponseBody
    public R<String> handleException(Exception ex) {
        log.error("全局异常处理器捕获到异常", ex);
        return R.fail("程序发生异常，请联系管理员", null);
    }

    @ExceptionHandler(DataAccessException.class)
    @ResponseBody
    public R<String> handleException(DataAccessException ex) {
        log.error("数据库操作发生异常", ex);
        return R.fail("数据格式异常", null);
    }

    @ExceptionHandler(SQLException.class)
    @ResponseBody
    public R<String> handleException(SQLException ex) {
        log.error("数据库操作发生异常", ex);
        return R.fail("数据库语句异常，请联系管理员", null);
    }

    @ExceptionHandler(NoResourceFoundException.class)
    @ResponseBody
    public R<String> handleException(NoResourceFoundException ex) {
        log.error("请求地址错误", ex);
        return R.fail("请求地址错误，请联系管理员", null);
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseBody
    public R<String> handleException(HttpMessageNotReadableException ex) {
        log.error("提交数据格式不正确", ex);
        return R.fail("提交数据格式不正确", null);
    }

    @ExceptionHandler(AppException.class)
    @ResponseBody
    public R<String> handleException(AppException ex) {

        R<String> r = R.fail(ex.getMessage(), null);
        r.setCode(ex.getCode());
        return r;
    }

    // json提交参数校验失败的错误处理
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public R<String> handleException(MethodArgumentNotValidException ex) {

        return R.fail(getValidateMessage(ex.getBindingResult().getAllErrors()), null);
    }

    // 表单提交参数校验失败的错误处理
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public R<String> handleException(BindException ex) {

        return R.fail(getValidateMessage(ex.getBindingResult().getAllErrors()), null);
    }

    private String getValidateMessage(List<ObjectError> errors) {
        StringBuilder sb = new StringBuilder();
        for (ObjectError error : errors) {
            sb.append(error.getDefaultMessage()).append(",");
        }
        if (!sb.isEmpty()) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }


}
